# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt


import frappe
from frappe import _
from frappe.utils import flt, add_years, getdate


from erpnext.accounts.report.financial_statements import (
    compute_growth_view_data,
    compute_margin_view_data,
    get_columns,
    get_data,
    get_filtered_list_for_consolidated_report,
    get_period_list,
)


def get_last_year_period_list(filters):
    """获取去年同期的期间列表"""
    if not (filters.get("last_fiscal_year") and filters.get("filter_based_on") == "Date Range"):
        return []

    try:
        # 复制过滤器并调整日期到上一年
        last_year_filters = filters.copy()
        
        # 处理开始日期
        if last_year_filters.get("period_start_date"):
            start_date = getdate(last_year_filters["period_start_date"])
            adjusted_start = add_years(start_date, -1)
            last_year_filters["period_start_date"] = adjusted_start.strftime("%Y-%m-%d")

        # 处理结束日期
        if last_year_filters.get("period_end_date"):
            end_date = getdate(last_year_filters["period_end_date"])
            adjusted_end = add_years(end_date, -1)
            last_year_filters["period_end_date"] = adjusted_end.strftime("%Y-%m-%d")

        # 调整财年（如果设置了的话）
        if last_year_filters.get("from_fiscal_year"):
            last_year_filters["from_fiscal_year"] = str(int(last_year_filters["from_fiscal_year"]) - 1)
        if last_year_filters.get("to_fiscal_year"):
            last_year_filters["to_fiscal_year"] = str(int(last_year_filters["to_fiscal_year"]) - 1)

        # 获取去年同期的期间列表
        return get_period_list(
            last_year_filters.from_fiscal_year,
            last_year_filters.to_fiscal_year,
            last_year_filters.period_start_date,
            last_year_filters.period_end_date,
            last_year_filters.filter_based_on,
            last_year_filters.periodicity,
            company=last_year_filters.company,
        )
    except Exception as e:
        frappe.log_error(
            f"获取上一财年期间列表时出错: {str(e)}",
            "Last Fiscal Year Period List Error"
        )
        return []


def execute(filters=None):
    # 复制filters避免修改原始对象
    filters = frappe._dict(filters.copy()) if filters else frappe._dict()
    
    # 获取当前期间列表
    period_list = get_period_list(
        filters.from_fiscal_year,
        filters.to_fiscal_year,
        filters.period_start_date,
        filters.period_end_date,
        filters.filter_based_on,
        filters.periodicity,
        company=filters.company,
    )

    # 获取去年同期期间列表
    last_year_period_list = get_last_year_period_list(filters)
    show_last_year = filters.get("last_fiscal_year") and filters.get("filter_based_on") == "Date Range" and last_year_period_list

    # 获取当前期间数据
    income = get_data(
        filters.company,
        "Income",
        "Credit",
        period_list,
        filters=filters,
        accumulated_values=filters.accumulated_values,
        ignore_closing_entries=True,
    )

    expense = get_data(
        filters.company,
        "Expense",
        "Debit",
        period_list,
        filters=filters,
        accumulated_values=filters.accumulated_values,
        ignore_closing_entries=True,
    )

    # 获取去年同期数据
    last_year_income = []
    last_year_expense = []
    if show_last_year:
        # 创建去年数据专用过滤器
        last_year_filters = filters.copy()
        if last_year_filters.get("from_fiscal_year"):
            last_year_filters["from_fiscal_year"] = str(int(last_year_filters["from_fiscal_year"]) - 1)
        if last_year_filters.get("to_fiscal_year"):
            last_year_filters["to_fiscal_year"] = str(int(last_year_filters["to_fiscal_year"]) - 1)
        
        last_year_income = get_data(
            filters.company,
            "Income",
            "Credit",
            last_year_period_list,
            filters=last_year_filters,
            accumulated_values=filters.accumulated_values,
            ignore_closing_entries=True,
        )

        last_year_expense = get_data(
            filters.company,
            "Expense",
            "Debit",
            last_year_period_list,
            filters=last_year_filters,
            accumulated_values=filters.accumulated_values,
            ignore_closing_entries=True,
        )

    # 应用模板映射与排序
    template = filters.get("profit_loss_template")
    if template:
        mapping = get_profit_loss_mapping(template)
        if mapping:
            income = apply_template_mapping(income, mapping, "Income")
            expense = apply_template_mapping(expense, mapping, "Expense")
            if show_last_year:
                last_year_income = apply_template_mapping(last_year_income, mapping, "Income")
                last_year_expense = apply_template_mapping(last_year_expense, mapping, "Expense")

    # 合并当前和去年数据
    if show_last_year:
        # 合并收入数据
        income = merge_period_data(income, last_year_income, period_list, last_year_period_list)
        # 合并支出数据
        expense = merge_period_data(expense, last_year_expense, period_list, last_year_period_list)

    # 计算净利润
    net_profit_loss = get_net_profit_loss(
        income, expense, period_list, filters.company, filters.presentation_currency, 
        last_year_period_list if show_last_year else None
    )

    data = []
    data.extend(income or [])
    data.extend(expense or [])
    if net_profit_loss:
        data.append(net_profit_loss)

    # 构建列 - 包含当前和去年同期
    columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
    
    # 添加去年同期列
    if show_last_year:
        last_year_columns = get_last_year_columns(
            filters.periodicity, 
            last_year_period_list, 
            filters.accumulated_values, 
            filters.company
        )
        # 合并列（跳过前两列，避免重复account和account_name）
        columns = columns + last_year_columns

    currency = filters.presentation_currency or frappe.get_cached_value(
        "Company", filters.company, "default_currency"
    )
    chart = get_chart_data(filters, columns, income, expense, net_profit_loss, currency)

    report_summary, primitive_summary = get_report_summary(
        period_list, filters.periodicity, income, expense, net_profit_loss, currency, filters
    )

    if filters.get("selected_view") == "Growth":
        compute_growth_view_data(data, period_list)

    if filters.get("selected_view") == "Margin":
        compute_margin_view_data(data, period_list, filters.accumulated_values)

    return columns, data, None, chart, report_summary, primitive_summary


def get_last_year_columns(periodicity, period_list, accumulated_values, company):
    """获取去年同期数据列定义"""
    columns = []
    for period in period_list:
        columns.append({
            "fieldname": f"last_year_{period.key}",
            "label": f"{period.label} (去年同期)",
            "fieldtype": "Currency",
            "options": frappe.get_cached_value("Company", company, "default_currency"),
            "width": 120
        })
    return columns


def merge_period_data(current_data, last_year_data, current_periods, last_year_periods):
    """合并当前期间和去年同期数据"""
    if not last_year_data or not current_data:
        return current_data

    # 创建去年数据的索引映射（优先使用reporting_item，其次使用account_name）
    last_year_index = {}
    for row in last_year_data:
        key = row.get("reporting_item") or row.get("account_name")
        if key:
            last_year_index[key] = row
    
    # 为每个当前期间的行添加去年同期数据
    for current_row in current_data:
        # 查找匹配的去年数据行
        key = current_row.get("reporting_item") or current_row.get("account_name")
        last_year_row = last_year_index.get(key)
        
        if last_year_row:
            # 复制去年同期的金额数据
            for period in last_year_periods:
                current_row[f"last_year_{period.key}"] = flt(last_year_row.get(period.key, 0))
        else:
            # 没有匹配数据时显式设置为0
            for period in last_year_periods:
                current_row[f"last_year_{period.key}"] = 0
    
    return current_data


def get_profit_loss_mapping(template):
    """从Profit Loss Config CN获取account与reporting_item的映射及sort_id"""
    if not template:
        return {}
    
    # 先检查模板是否存在
    if not frappe.db.exists("Profit Loss Config CN", template):
        frappe.log_error(f"模板不存在: {template}", "Profit Loss Mapping Error")
        return {}
    
    # 执行查询时增加错误捕获
    try:
        mapping_items = frappe.db.sql("""
            SELECT 
                `tabProfit Loss Config Item CN`.`account` AS account,
                `tabProfit Loss Config Item CN`.`reporting_item` AS reporting_item,
                `tabProfit Loss Config Item CN`.`sort_id` AS sort_id,
                `tabProfit Loss Config Item CN`.`account_type` AS account_type
            FROM `tabProfit Loss Config Item CN`
            WHERE `tabProfit Loss Config Item CN`.`parent` = %s
            AND `tabProfit Loss Config Item CN`.`account` IS NOT NULL
            ORDER BY `tabProfit Loss Config Item CN`.`sort_id` ASC
        """, (template), as_dict=True)
        
        mapping = {}
        for item in mapping_items:
            account = item.get("account")
            if account:
                mapping[account] = item
            else:
                frappe.log_error(
                    f"发现无效记录（account为空）: {str(item)}",
                    "Profit Loss Mapping Invalid Record"
                )
        
        return mapping
    
    except Exception as e:
        frappe.log_error(
            f"查询映射时出错: {str(e)}，模板: {template}",
            "Profit Loss Mapping Query Error"
        )
        return {}


def apply_template_mapping(data, mapping, account_type):
    """按Reporting Item分组重组数据"""
    if not data:
        return []
    
    # 1. 分组：按Reporting Item归类
    grouped = {}
    for row in data:
        account = row.get("account")
        is_group = row.get("is_group", False)
        
        if account in mapping and mapping[account]["account_type"] == account_type:
            reporting_item = mapping[account]["reporting_item"] or "undefined"
            sort_id = mapping[account]["sort_id"]
        else:
            if is_group:
                continue
            reporting_item = "undefined"
            sort_id = 9999
        
        if reporting_item not in grouped:
            grouped[reporting_item] = {
                "sort_id": sort_id,
                "children": []
            }
        
        child_row = row.copy()
        child_row["reporting_item"] = reporting_item
        child_row["sort_id"] = sort_id
        child_row["is_group"] = False
        child_row["parent"] = reporting_item
        grouped[reporting_item]["children"].append(child_row)
    
    # 2. 排序：先按分组的sort_id，再按子项的sort_id
    sorted_groups = sorted(grouped.items(), key=lambda x: x[1]["sort_id"])
    
    # 3. 构建最终数据结构
    result = []
    for reporting_item, group_data in sorted_groups:
        # 计算当前分组下所有子项的金额总和
        totals = {}
        for child in group_data["children"]:
            for key, value in child.items():
                if key in ("account_name", "reporting_item", "is_group", "parent", "sort_id", "indent", "account"):
                    continue
                totals[key] = flt(totals.get(key, 0)) + flt(value)
        
        # 父项：Reporting Item
        parent_row = {
            "account_name": reporting_item,
            "reporting_item": reporting_item,
            "is_group": True,
            "parent": "",
            "sort_id": group_data["sort_id"],
            "indent": 0,** totals
        }
        if group_data["children"]:
            parent_row["currency"] = group_data["children"][0].get("currency")
        
        result.append(parent_row)
        
        # 子项：对应Account
        sorted_children = sorted(group_data["children"], key=lambda x: x.get("sort_id", 9999))
        for child in sorted_children:
            child["indent"] = 1
            result.append(child)
    
    return result


def get_report_summary(
    period_list, periodicity, income, expense, net_profit_loss, currency, filters, consolidated=False
):
    net_income, net_expense, net_profit = 0.0, 0.0, 0.0

    if filters.get("accumulated_in_group_company"):
        period_list = get_filtered_list_for_consolidated_report(filters, period_list)

    if filters.accumulated_values:
        key = period_list[-1].key if period_list else None
        if income and key:
            net_income = income[-2].get(key)
        if expense and key:
            net_expense = expense[-2].get(key)
        if net_profit_loss and key:
            net_profit = net_profit_loss.get(key)
    else:
        for period in period_list:
            key = period if consolidated else period.key
            if income:
                net_income += income[-2].get(key) or 0
            if expense:
                net_expense += expense[-2].get(key) or 0
            if net_profit_loss:
                net_profit += net_profit_loss.get(key) or 0

    if len(period_list) == 1 and periodicity == "Yearly":
        profit_label = _("Profit This Year")
        income_label = _("Total Income This Year")
        expense_label = _("Total Expense This Year")
    else:
        profit_label = _("Net Profit")
        income_label = _("Total Income")
        expense_label = _("Total Expense")

    return [
        {"value": net_income, "label": income_label, "datatype": "Currency", "currency": currency},
        {"type": "separator", "value": "-"},
        {"value": net_expense, "label": expense_label, "datatype": "Currency", "currency": currency},
        {"type": "separator", "value": "=", "color": "blue"},
        {
            "value": net_profit,
            "indicator": "Green" if net_profit > 0 else "Red",
            "label": profit_label,
            "datatype": "Currency",
            "currency": currency,
        },
    ], net_profit


def get_net_profit_loss(income, expense, period_list, company, currency=None, 
                       last_year_period_list=None, consolidated=False):
    total = 0
    net_profit_loss = {
        "account_name": "'" + _("Profit for the year") + "'",
        "account": "'" + _("Profit for the year") + "'",
        "warn_if_negative": True,
        "currency": currency or frappe.get_cached_value("Company", company, "default_currency"),
    }

    has_value = False

    # 计算当前期间净利润
    for period in period_list:
        key = period if consolidated else period.key
        total_income = flt(income[-2][key], 3) if (income and len(income) >= 2) else 0
        total_expense = flt(expense[-2][key], 3) if (expense and len(expense) >= 2) else 0

        net_profit_loss[key] = total_income - total_expense

        if net_profit_loss[key]:
            has_value = True

        total += flt(net_profit_loss[key])
    net_profit_loss["total"] = total

    # 计算去年同期净利润
    if last_year_period_list:
        last_year_total = 0
        for period in last_year_period_list:
            key = period if consolidated else period.key
            last_year_key = f"last_year_{key}"
            
            total_income = flt(income[-2][last_year_key], 3) if (income and len(income) >= 2) else 0
            total_expense = flt(expense[-2][last_year_key], 3) if (expense and len(expense) >= 2) else 0

            net_profit_loss[last_year_key] = total_income - total_expense
            last_year_total += flt(net_profit_loss[last_year_key])
        
        net_profit_loss[f"last_year_total"] = last_year_total
        has_value = True

    if has_value:
        return net_profit_loss


def get_chart_data(filters, columns, income, expense, net_profit_loss, currency):
    # 仅包含当前期间数据用于图表
    labels = []
    for d in columns[2:]:
        if not d.get("fieldname", "").startswith("last_year_"):
            labels.append(d.get("label"))

    income_data, expense_data, net_profit = [], [], []

    for p in columns[2:]:
        fieldname = p.get("fieldname")
        if fieldname and fieldname.startswith("last_year_"):
            continue
            
        if income and len(income) >= 2:
            income_data.append(income[-2].get(fieldname))
        if expense and len(expense) >= 2:
            expense_data.append(expense[-2].get(fieldname))
        if net_profit_loss:
            net_profit.append(net_profit_loss.get(fieldname))

    datasets = []
    if income_data:
        datasets.append({"name": _("Income"), "values": income_data})
    if expense_data:
        datasets.append({"name": _("Expense"), "values": expense_data})
    if net_profit:
        datasets.append({"name": _("Net Profit/Loss"), "values": net_profit})

    chart = {"data": {"labels": labels, "datasets": datasets}}

    if not filters.accumulated_values:
        chart["type"] = "bar"
    else:
        chart["type"] = "line"

    chart["fieldtype"] = "Currency"
    chart["options"] = "currency"
    chart["currency"] = currency

    return chart
    